/*!
 * \file stomp_parse.c
 *
 * \brief stomp解析
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 * ct管理用共通函数
 *
 * \version 2.0
 * \author geyh
 * \date 2015/10/14
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "stomp_comm.h"
#include "stomp_parse.h"

#define STOMP_SEND                          1
#define STOMP_SUBSCRIBE                     2
#define STOMP_MESSAGE                       3
#define STOMP_CONNECT                       4
#define STOMP_CONNECTED                     5
#define STOMP_OTHERS                        6
#define STOMP_DISCONNECT                    7
#define STOMP_ERROR                         8
/*!
 * 数据类型判断
 *
 * \p_data_in       (输入数据)
 * \i_data_len      (数据长度)
 * \p_st_private    (私有数据)
 *
 * \return FR_FAIL:失败\n
 *         FR_SUCC:成功
 *
 */
FR_STATIC int __stomp_action_detect(char *p_data_in, int i_data_len, L7session_stomp_private *p_st_private)
{
    if(p_data_in == NULL || i_data_len == 0 || p_st_private == NULL)
        return FR_FAIL;

    switch(i_data_len)
    {
        //SEND
        case 4:
            if(strncasecmp(p_data_in, "SEND", 4) == 0)
                p_st_private->i_action = STOMP_SEND;
            else
                p_st_private->i_action = STOMP_OTHERS;
            break;

        //ERROR
        case 5:
            if (strncasecmp(p_data_in, "ERROR", 5) == 0)
                p_st_private->i_action = STOMP_ERROR;
            break;

        //MESSAGE  CONNECT
        case 7:
            if(strncasecmp(p_data_in, "MESSAGE", 7) == 0)
                p_st_private->i_action = STOMP_MESSAGE;
            else if(strncasecmp(p_data_in, "CONNECT", 7) == 0)
                p_st_private->i_action = STOMP_CONNECT;
            else
                p_st_private->i_action = STOMP_OTHERS;
            break;

        //SUBSCRIBE  CONNECTED
        case 9:
            if(strncasecmp(p_data_in, "SUBSCRIBE", 9) == 0)
                p_st_private->i_action = STOMP_SUBSCRIBE;
            else if(strncasecmp(p_data_in, "CONNECTED", 9) == 0)
                p_st_private->i_action = STOMP_CONNECTED;
            else
                p_st_private->i_action = STOMP_OTHERS;
            break;

        case 10:
            if(strncasecmp(p_data_in, "DISCONNECT", 10) == 0)
                p_st_private->i_action = STOMP_DISCONNECT;
            break;

        default:
            p_st_private->i_action = STOMP_OTHERS;
            break;
    }

    return FR_SUCC;

}

/*!
 * 通信过程数据解析
 *
 * \pp_data_in           (入力参数)
 * \ui_data_len          (数据长度)
 * \p_st_body_data       (数据上报链表)
 * \p_st_private         (私有数据)
 *
 * \return APM_L7_ANALYZE_FAIL:失败\n
 *         APM_L7_ANALYZE_TODO:数据包解析未结束\n
 *         APM_L7_ANALYZE_SUCC:成功
 *
 */
int stomp_parse(char **pp_data_in, int *p_i_data_len, Frreport_body_data *p_st_body_data, L7session_stomp_private *p_st_private)
{
    int i_ret = 0;
    char *p_pos = NULL;
    int i_data_len = 0, i_data_tmp = 0;
    char *p_action = NULL, *p_data_in_tmp = NULL;
    int i_value_len = 0;
    char *p_data_in = NULL;

    if(pp_data_in == NULL || *pp_data_in == NULL || p_i_data_len == NULL || p_st_body_data == NULL || p_st_private == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_data_in = *pp_data_in;
    i_data_len = *p_i_data_len;

    if(i_data_len == 0)
        return APM_L7_ANALYZE_SUCC;

    if(p_st_private->p_str_pre)
    {
        i_data_tmp = p_st_private->p_str_pre->ui_len + i_data_len;
        p_data_in_tmp = (char *)frmalloc(i_data_tmp + 1);
        if(p_data_in_tmp == NULL)
            return APM_L7_ANALYZE_FAIL;

        memcpy(p_data_in_tmp, p_st_private->p_str_pre->p_str, p_st_private->p_str_pre->ui_len);
        memcpy(p_data_in_tmp + p_st_private->p_str_pre->ui_len, p_data_in, i_data_len);

        p_data_in = p_data_in_tmp;
        i_data_len = i_data_tmp;

        frstr_free (&p_st_private->p_str_pre);
    }

    //判断数据包类型
    if(p_st_private->i_action == 0)
    {
        p_pos = (char *)memchr(p_data_in, '\x0a', i_data_len);
        if(p_pos == NULL)
        {
            if(p_st_private->p_str_pre)
                frstr_free(&p_st_private->p_str_pre);

            p_st_private->p_str_pre = frstr_new(i_data_len);
            if(p_st_private->p_str_pre == NULL)
            {
                if(p_data_in_tmp)
                    frfree (p_data_in_tmp);
                return APM_L7_ANALYZE_FAIL;
            }

            i_ret = frstr_append(p_st_private->p_str_pre, p_data_in, (unsigned int)i_data_len);
            if(p_data_in_tmp)
                frfree (p_data_in_tmp);
            return i_ret == FR_SUCC ? APM_L7_ANALYZE_TODO : APM_L7_ANALYZE_FAIL;

        }

        i_value_len = p_pos - p_data_in;
        p_action =(char *)frmalloc(i_value_len + 1);
        if(p_action == NULL)
        {
            if(p_data_in_tmp)
                frfree (p_data_in_tmp);
            return APM_L7_ANALYZE_FAIL;
        }

        snprintf(p_action, i_value_len + 1, "%s", p_data_in);

        //action判断
        i_ret = __stomp_action_detect(p_action, i_value_len, p_st_private);
        frfree(p_action);
        if(i_ret == FR_FAIL)
        {
            if(p_data_in_tmp)
                frfree (p_data_in_tmp);
            return APM_L7_ANALYZE_FAIL;
        }

        i_data_len -= (i_value_len + 1);
        p_data_in += (i_value_len + 1);
    }


    switch(p_st_private->i_action)
    {
        case STOMP_SEND:
            i_ret = stomp_send_parse(&p_data_in, &i_data_len, p_st_body_data, p_st_private);
            p_st_private->i_report = 1;
            break;

        case STOMP_MESSAGE:
            i_ret = stomp_message_parse(&p_data_in, &i_data_len, p_st_body_data, p_st_private);
            p_st_private->i_report = 1;
            break;

        case STOMP_SUBSCRIBE:
            i_ret = stomp_subscribe_parse(&p_data_in, &i_data_len, p_st_body_data, p_st_private);
            //如果是queue  sub动作不上报
            if(p_st_private->is_topic)
            {
                p_st_private->i_report = 1;
                p_st_private->i_response_required = 1;
            }

            break;

        case STOMP_CONNECT:
            p_st_private->i_flag_data_type = FRLOGIN_START;
            i_ret = stomp_connect_parse(&p_data_in, &i_data_len, p_st_body_data, p_st_private);
            break;

        case STOMP_CONNECTED:
            i_ret = stomp_connected_parse(&p_data_in, &i_data_len, p_st_body_data, p_st_private);
            break;

        case STOMP_ERROR:
            p_st_private->i_flag_data_type = FRLOGIN_FAIL;
            i_ret = stomp_others_parse(&p_data_in, &i_data_len, p_st_body_data, p_st_private);
            break;

        case STOMP_DISCONNECT:
            p_st_private->i_flag_data_type = FRLOGOUT_END;
            i_ret = stomp_others_parse(&p_data_in, &i_data_len, p_st_body_data, p_st_private);
            break;

        case STOMP_OTHERS:
            i_ret = stomp_others_parse(&p_data_in, &i_data_len, p_st_body_data, p_st_private);
            break;

        default:
            if(p_data_in_tmp)
                frfree(p_data_in_tmp);

            return APM_L7_ANALYZE_FAIL;

    }

    *pp_data_in = *pp_data_in + *p_i_data_len - i_data_len;
    *p_i_data_len = i_data_len;

    if(p_data_in_tmp)
        frfree(p_data_in_tmp);

    return i_ret;

}

